﻿// Copyright (c) JosephZheng. All rights reserved. See License.txt in the project root for license

using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using Lyra.Cache.Client;
using Lyra.Cache.Client.Enum;
using Lyra.Cache.HelperTool.SubForm;
using Lyra.Cache.Server.Interface;
using Lyra.Cache.Server.Interface.Contract;
using Lyra.Cache.Server.Interface.Contract.ClientResult;
using Lyra.Cache.Server.Interface.Contract.ServerResult;
using MessageBoxHelperLib;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Lyra.Cache.HelperTool
{
    public partial class CacheHelperTool : Form
    {
        private Dictionary<string, Type> _schemas = null;

        private Dictionary<string, List<string>> _views = null;

        private CodeDomProvider _provider = CodeDomProvider.CreateProvider("CSharp", new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } });
        private CompilerParameters _parameters = new CompilerParameters()
        {
            GenerateInMemory = true,
            GenerateExecutable = false,
        };

        public CacheHelperTool()
        {
            InitializeComponent();
            _schemas = new Dictionary<string, Type>();
            _views = new Dictionary<string, List<string>>();
            this.tscbEnableLockSession.SelectedIndex = 1;
            this.tscbRAIM.SelectedIndex = 1;
            this.tscbRegion.SelectedIndex = 0;
            
            Assembly[] AssemblieLoadeds = AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly assembly in AssemblieLoadeds)
            {
                _parameters.ReferencedAssemblies.Add(assembly.Location);
            }
            _parameters.ReferencedAssemblies.Add("Lyra.Cache.Client.dll");
            _parameters.ReferencedAssemblies.Add("Lyra.Cache.Server.Interface.dll");
        }

        private RAIM GetRAIMSelected()
        {
            switch (this.tscbRAIM.SelectedIndex)
            {
                case 0:
                    return RAIM.Mode0;
                case 1:
                    return RAIM.Mode1;
                case 2:
                    return RAIM.Mode5;
                case 3:
                    return RAIM.Mode5Plus;
                default:
                    return RAIM.Mode1;
            }
        }

        private void DisableFunction()
        {
            
        }

        private void tsbQuery_Click(object sender, EventArgs e)
        {
            if (this.tscbRegion.SelectedIndex != 0)
            {
                this.Enabled = false;
                try
                {
                    this.dgvCache.Rows.Clear();
                    CacheClient client = new CacheClient(this.tstbServers.Text.Trim().Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries), GetRAIMSelected());

                    string guid = this.tscbEnableLockSession.SelectedIndex == 0 ? Guid.NewGuid().ToString("N") : null;
                    int lockseconds = 0;
                    int.TryParse(this.tstbLockSeconds.Text, out lockseconds);
                    GetWithFilterClientResult<string, GetWithFilterServerResult> result = null;
                    if (this.tscbView.SelectedIndex == 0)
                    {
                        if (string.IsNullOrWhiteSpace(this.tstbOrder.Text))
                        {
                            result = client.GetWithFilter<string>(this.tscbRegion.SelectedItem.ToString(), this.tstbFilter.Text, guid, lockseconds);
                        }
                        else
                        {
                            int top = 0;
                            if (int.TryParse(this.tstbTop.Text, out top))
                            {
                                result = client.GetWithFilterAndTop<string>(this.tscbRegion.SelectedItem.ToString(), this.tstbFilter.Text, top, this.tstbOrder.Text.Trim(), guid, lockseconds);
                            }
                            else
                            {
                                MessageBoxHelper.ShowError("wrong top count!");
                                return;
                            }
                        }
                    }
                    else
                    {
                        if (string.IsNullOrWhiteSpace(this.tstbOrder.Text))
                        {
                            result = client.GetWithFilterUsingView<string>(this.tscbRegion.SelectedItem.ToString(), this.tstbFilter.Text, this.tscbView.SelectedItem.ToString(), guid, lockseconds);
                        }
                        else
                        {
                            int top = 0;
                            if (int.TryParse(this.tstbTop.Text, out top))
                            {
                                result = client.GetWithFilterAndTopUsingView<string>(this.tscbRegion.SelectedItem.ToString(), this.tstbFilter.Text, this.tscbView.SelectedItem.ToString(), top, this.tstbOrder.Text.Trim(), guid, lockseconds);
                            }
                            else
                            {
                                MessageBoxHelper.ShowError("wrong top count!");
                                return;
                            }
                        }
                    }

                    this.tstbLockSession.Text = guid;

                    if (result.HasError)
                    {
                        if (result.HasError)
                        {
                            StringBuilder sb = new StringBuilder();
                            sb.AppendLine("query occur some error!");
                            sb.AppendLine("==============================");
                            foreach (KeyValuePair<string, GetWithFilterServerResult> kvp in result.ServerResults)
                            {
                                sb.AppendLine(string.Concat("server:", kvp.Key));
                                sb.AppendLine(string.Concat("    code:", kvp.Value.Code));
                            }
                            new ErrorForm(sb.ToString()).ShowDialog();
                        }
                    }

                    foreach (KeyValuePair<string, CacheObject<string>> kvp in result.Objects)
                    {
                        try
                        {
                            List<object> values = new List<object>();
                            values.Add(kvp.Key);
                            JObject obj = JObject.Parse(kvp.Value.Data);
                            foreach (DataGridViewColumn column in this.dgvCache.Columns)
                            {
                                if (column.HeaderText != "_key")
                                {
                                    JToken value = obj.Children().SingleOrDefault(x => (x as JProperty).Name == column.HeaderText);
                                    if (value == null) values.Add(null);
                                    else
                                    {
                                        values.Add(((value as JProperty).Value as JValue).Value.ToString());
                                    }
                                }
                            }

                            this.dgvCache.Rows.Add(values.ToArray());
                        }
                        catch (Exception ex)
                        {
                            MessageBoxHelper.ShowWarning(ex.Message);
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBoxHelper.ShowError(ex.Message);
                }
                finally
                {
                    this.Enabled = true;
                }
            }
        }

        private void tsbAdd_Click(object sender, EventArgs e)
        {
            if (this.tscbRegion.SelectedIndex != 0)
            {
                this.Enabled = false;
                try
                {
                    AddCacheForm form = new AddCacheForm(_schemas[this.tscbRegion.SelectedItem.ToString()]);
                    if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        CacheClient client = new CacheClient(this.tstbServers.Text.Trim().Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries), GetRAIMSelected());
                        ClientResult<ServerResult> result = client.Add(this.tscbRegion.SelectedItem.ToString(), form.tstbKey.Text.Trim(), form.CacheObject, TimeSpan.FromSeconds(double.Parse(this.tstbExpireSeconds.Text)));
                        if (result.HasError)
                        {
                            StringBuilder sb = new StringBuilder();
                            sb.AppendLine("add occur some error!");
                            sb.AppendLine("==============================");
                            foreach (KeyValuePair<string, ServerResult> kvp in result.ServerResults)
                            {
                                sb.AppendLine(string.Concat("server:", kvp.Key));
                                sb.AppendLine(string.Concat("    code:", kvp.Value.Code));
                            }
                            new ErrorForm(sb.ToString()).ShowDialog();
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBoxHelper.ShowError(ex.Message);
                }
                finally
                {
                    this.Enabled = true;
                }
            }
            else
            {
                MessageBoxHelper.ShowInfo("need select region first!");
            }
        }

        private void tsbSet_Click(object sender, EventArgs e)
        {
            if (this.tscbRegion.SelectedIndex != 0)
            {
                if (this.dgvCache.SelectedRows.Count != 0)
                {
                    this.Enabled = false;
                    Dictionary<string, string> values = new Dictionary<string, string>();
                    try
                    {
                        foreach (DataGridViewColumn col in this.dgvCache.Columns)
                        {
                            string cell = this.dgvCache.SelectedRows[0].Cells[col.Name].Value as string;
                            if (!string.IsNullOrWhiteSpace(cell))
                            {
                                values.Add(col.HeaderText, cell);
                            }
                        }

                        SetCacheForm form = new SetCacheForm(this.dgvCache.SelectedRows[0].Cells[0].Value.ToString(), _schemas[this.tscbRegion.SelectedItem.ToString()], values);
                        if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                        {
                            CacheClient client = new CacheClient(this.tstbServers.Text.Trim().Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries), GetRAIMSelected());
                            ClientResult<ServerResult> result = client.Set(this.tscbRegion.SelectedItem.ToString(), form.tstbKey.Text.Trim(), form.CacheObject, TimeSpan.FromSeconds(double.Parse(this.tstbExpireSeconds.Text)), string.IsNullOrWhiteSpace(this.tstbLockSession.Text) ? null : this.tstbLockSession.Text, true);
                            if (result.HasError)
                            {
                                StringBuilder sb = new StringBuilder();
                                sb.AppendLine("create occur some error!");
                                sb.AppendLine("==============================");
                                foreach (KeyValuePair<string, ServerResult> kvp in result.ServerResults)
                                {
                                    sb.AppendLine(string.Concat("server:", kvp.Key));
                                    sb.AppendLine(string.Concat("    code:", kvp.Value.Code));
                                }
                                new ErrorForm(sb.ToString()).ShowDialog();
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBoxHelper.ShowError(ex.Message);
                    }
                    finally
                    {
                        this.Enabled = true;
                    }
                }
            }
            else
            {
                MessageBoxHelper.ShowInfo("need select region first!");
            }
        }

        private void tsbRemove_Click(object sender, EventArgs e)
        {
            if(this.tscbRegion.SelectedIndex != 0)
            {
                if (this.dgvCache.SelectedRows.Count != 0)
                {
                    this.Enabled = false;
                    try
                    {
                        if (MessageBoxHelper.ShowQuery(string.Format("remove cache item key : {0} ?", this.dgvCache.SelectedRows[0].Cells[0].Value.ToString())) == System.Windows.Forms.DialogResult.Yes)
                        {
                            CacheClient client = new CacheClient(this.tstbServers.Text.Trim().Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries), GetRAIMSelected());
                            ClientResult<ServerResult> result = client.Remove(this.tscbRegion.SelectedItem.ToString(), this.dgvCache.SelectedRows[0].Cells[0].Value.ToString(), string.IsNullOrWhiteSpace(this.tstbLockSession.Text) ? null : this.tstbLockSession.Text);
                            if (result.HasError)
                            {
                                StringBuilder sb = new StringBuilder();
                                sb.AppendLine("remove occur some error!");
                                sb.AppendLine("==============================");
                                foreach (KeyValuePair<string, ServerResult> kvp in result.ServerResults)
                                {
                                    sb.AppendLine(string.Concat("server:", kvp.Key));
                                    sb.AppendLine(string.Concat("    code:", kvp.Value.Code));
                                }
                                new ErrorForm(sb.ToString()).ShowDialog();
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBoxHelper.ShowError(ex.Message);
                    }
                    finally
                    {
                        this.Enabled = true;
                    }
                }
            }
            else
            {
                MessageBoxHelper.ShowInfo("need select region first!");
            }
        }

        private void tsbCount_Click(object sender, EventArgs e)
        {
            if (this.tscbRegion.SelectedIndex != 0)
            {
                this.Enabled = false;
                try
                {
                    CacheClient client = new CacheClient(this.tstbServers.Text.Trim().Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries), GetRAIMSelected());
                    StringBuilder sb = new StringBuilder();
                    CountClientResult<CountServerResult> result = client.Count(this.tscbRegion.SelectedItem.ToString());
                    if (result.HasError)
                    {
                        sb.AppendLine("query count occur some error!");
                        sb.AppendLine("==============================");
                        foreach (KeyValuePair<string, CountServerResult> kvp in result.ServerResults)
                        {
                            sb.AppendLine(string.Concat("server:", kvp.Key));
                            sb.AppendLine(string.Concat("    code:", kvp.Value.Code));
                            sb.AppendLine(string.Concat("    count:", kvp.Value.Count));
                        }
                    }
                    else
                    {
                        foreach (KeyValuePair<string, long> kvp in result.Counts)
                        {
                            sb.AppendLine(string.Concat("server:", kvp.Key));
                            sb.AppendLine(string.Concat("    count:", kvp.Value));
                        }
                    }
                    new InformationForm(sb.ToString()).ShowDialog();
                }
                catch (Exception ex)
                {
                    MessageBoxHelper.ShowError(ex.Message);
                }
                finally
                {
                    this.Enabled = true;
                }
            }
            else
            {
                MessageBoxHelper.ShowInfo("need select region first!");
            }
        }

        private void tsbStatistics_Click(object sender, EventArgs e)
        {
            this.Enabled = false;
            try
            {
                CacheClient client = new CacheClient(this.tstbServers.Text.Trim().Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries), GetRAIMSelected());
                StringBuilder sb = new StringBuilder();
                ClientResult<StatisticsServerResult> result = client.Statistics();
                if (result.HasError)
                {
                    sb.AppendLine("query count occur some error!");
                    sb.AppendLine("==============================");
                }
                foreach (KeyValuePair<string, StatisticsServerResult> kvp in result.ServerResults)
                {
                    sb.AppendLine(string.Concat("server:", kvp.Key));
                    sb.AppendLine(string.Concat("    code:", kvp.Value.Code));
                    foreach (KeyValuePair<string, CacheStatistics> kvpc in kvp.Value.Statistics)
                    {
                        sb.AppendLine(string.Concat("    region:", kvpc.Key));
                        sb.AppendLine(string.Concat("      schema:", kvpc.Value.Schema));
                        sb.AppendLine(string.Concat("      count:", kvpc.Value.Count));
                        sb.AppendLine(string.Concat("      operation:", kvpc.Value.Operation));
                    }
                }
                new InformationForm(sb.ToString()).ShowDialog();
            }
            catch (Exception ex)
            {
                MessageBoxHelper.ShowError(ex.Message);
            }
            finally
            {
                this.Enabled = true;
            }
        }

        private void tstbRegion_TextChanged(object sender, EventArgs e)
        {
            this.dgvCache.Rows.Clear();
            this.dgvCache.Columns.Clear();
            this._schemas = null;
        }

        private void tsbCreate_Click(object sender, EventArgs e)
        {
            CreateSchemaForm form = new CreateSchemaForm();
            if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                this.Enabled = false;
                try
                {
                    CacheClient client = new CacheClient(this.tstbServers.Text.Trim().Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries), GetRAIMSelected());
                    StringBuilder sbtype = new StringBuilder();
                    string classname = GetRandomClassName();
                    List<string> columnnames = new List<string>();

                    sbtype.AppendLine("//code generate for cache contract");
                    sbtype.AppendLine("using System;");
                    sbtype.AppendLine("using System.Collections.Generic;");
                    sbtype.AppendLine("using System.Text;");
                    sbtype.AppendLine("using Lyra.Cache.Client;");
                    sbtype.AppendLine("using Lyra.Cache.Client.Attribute;");
                    sbtype.AppendLine("namespace Lyra.Cache.HelperTool {");
                    sbtype.AppendLine("\t[CacheContract]");
                    sbtype.AppendLine(string.Concat("\tpublic class ", classname, " {"));
                    foreach (KeyValuePair<string, string> kvp in form.Schema)
                    {
                        columnnames.Add(kvp.Key.ToLower());
                        sbtype.AppendLine("\t\t[CacheMember]");
                        sbtype.AppendLine(string.Concat("\t\tpublic ", kvp.Value, " ", kvp.Key, " {get;set;}"));
                    }
                    sbtype.AppendLine("\t}");
                    sbtype.AppendLine("}");

                    ConfirmSchemaForm form2 = new ConfirmSchemaForm();
                    form2.txtCode.Text = sbtype.ToString();
                    if (form2.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        if (!this._schemas.ContainsKey(form.tstbRegion.Text.Trim()))
                        {
                            CompilerResults cr = _provider.CompileAssemblyFromSource(_parameters, form2.txtCode.Text);
                            if (cr.Errors.HasErrors)
                            {
                                StringBuilder sb = new StringBuilder();
                                foreach (CompilerError ce in cr.Errors)
                                {
                                    sb.Append(ce.ToString());
                                }
                                MessageBoxHelper.ShowError(string.Concat("compile code error",sb.ToString()));
                                return;
                            }
                            else
                            {
                                Assembly asm = cr.CompiledAssembly;
                                Type t = asm.GetType(string.Concat("Lyra.Cache.HelperTool.", classname));
                                if (t != null)
                                {
                                    _schemas.Add(form.tstbRegion.Text.Trim(), t);

                                    if (form.View != null && form.View.Count != 0)
                                    {
                                        foreach (KeyValuePair<string, string> view in form.View)
                                        {
                                            List<string> checklist = new List<string>();
                                            bool checkpass = true;
                                            foreach (string columnname in view.Value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                                            {
                                                string processedname = columnname.ToLower().Replace("asc", string.Empty).Replace("desc", string.Empty).Trim();
                                                if (!columnnames.Contains(processedname))
                                                {
                                                    checkpass = false;
                                                    break;
                                                }
                                                else
                                                {
                                                    if (checklist.Contains(processedname))
                                                    {
                                                        checkpass = false;
                                                        break;
                                                    }
                                                    else checklist.Add(processedname);
                                                }
                                            }
                                            if (!checkpass)
                                            {
                                                MessageBoxHelper.ShowError("wrong view setting!");
                                                return;
                                            }
                                            this._views.Add(form.tstbRegion.Text.Trim(), form.View.Keys.ToList());
                                        }
                                    }

                                    RefreshRegionCombox(form.tstbRegion.Text.Trim());
                                }
                                else
                                {
                                    MessageBoxHelper.ShowError("compile code error");
                                    return;
                                }
                            }

                            if (form.SendToServer)
                            {
                                ClientResult<ServerResult> result = client.Create(form.tstbRegion.Text.Trim(), _schemas[form.tstbRegion.Text.Trim()], form.View);
                                if (result.HasError)
                                {
                                    StringBuilder sb = new StringBuilder();
                                    sb.AppendLine("create occur some error!");
                                    sb.AppendLine("==============================");
                                    foreach (KeyValuePair<string, ServerResult> kvp in result.ServerResults)
                                    {
                                        sb.AppendLine(string.Concat("server:", kvp.Key));
                                        sb.AppendLine(string.Concat("    code:", kvp.Value.Code));
                                    }
                                    new ErrorForm(sb.ToString()).ShowDialog();
                                }
                            }
                        }
                        else
                        {
                            MessageBoxHelper.ShowError("region had exist");
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBoxHelper.ShowError(ex.Message);
                }
                finally
                {
                    this.Enabled = true;
                }
            }
        }

        private void RefreshRegionCombox(string selected)
        {
            this.tscbRegion.Items.Clear();
            this.tscbRegion.Items.Add("<==Select==>");
            foreach (KeyValuePair<string, Type> kvp in _schemas) this.tscbRegion.Items.Add(kvp.Key);
            if (_schemas.ContainsKey(selected)) this.tscbRegion.SelectedItem = selected;
            else this.tscbRegion.SelectedIndex = 0;
        }

        private string GetRandomClassName()
        {
            StringBuilder sb = new StringBuilder();
            Random r = new Random();
            for (int i = 0; i < 16; i++)
            {
                sb.Append((char)r.Next(65, 91));
            }
            return sb.ToString();
        }

        private void tsbDrop_Click(object sender, EventArgs e)
        {
            if (this.tscbRegion.SelectedIndex != 0)
            {
                if (MessageBoxHelper.ShowQuery(string.Format("drop region : {0} ?", this.tscbRegion.SelectedItem.ToString())) == System.Windows.Forms.DialogResult.Yes)
                {
                    this.Enabled = false;
                    try
                    {
                        CacheClient client = new CacheClient(this.tstbServers.Text.Trim().Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries), GetRAIMSelected());
                        ClientResult<ServerResult> result = client.Drop(this.tscbRegion.SelectedItem.ToString());
                        if (result.HasError)
                        {
                            StringBuilder sb = new StringBuilder();
                            sb.AppendLine("drop occur some error!");
                            sb.AppendLine("==============================");
                            foreach (KeyValuePair<string, ServerResult> kvp in result.ServerResults)
                            {
                                sb.AppendLine(string.Concat("server:", kvp.Key));
                                sb.AppendLine(string.Concat("    code:", kvp.Value.Code));
                            }
                            new ErrorForm(sb.ToString()).ShowDialog();
                        }
                        _schemas.Remove(this.tscbRegion.SelectedItem.ToString());
                        RefreshRegionCombox(null);
                    }
                    catch (Exception ex)
                    {
                        MessageBoxHelper.ShowError(ex.Message);
                    }
                    finally
                    {
                        this.Enabled = true;
                    }
                }
            }
        }

        private void tsbMemory_Click(object sender, EventArgs e)
        {
            this.Enabled = false;
            try
            {
                CacheClient client = new CacheClient(this.tstbServers.Text.Trim().Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries), GetRAIMSelected());
                StringBuilder sb = new StringBuilder();
                ClientResult<MemoryServerResult> result = client.Memory();
                if (result.HasError)
                {
                    sb.AppendLine("query memory occur some error!");
                    sb.AppendLine("==============================");
                }
                foreach (KeyValuePair<string, MemoryServerResult> kvp in result.ServerResults)
                {
                    sb.AppendLine(string.Concat("server:", kvp.Key));
                    sb.AppendLine(string.Concat("    code:", kvp.Value.Code));
                    sb.AppendLine(string.Concat("    used:", kvp.Value.Used));
                    sb.AppendLine(string.Concat("    limit:", kvp.Value.Limit));
                }
                new InformationForm(sb.ToString()).ShowDialog();
            }
            catch (Exception ex)
            {
                MessageBoxHelper.ShowError(ex.Message);
            }
            finally
            {
                this.Enabled = true;
            }
        }

        private void tscbRegion_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.Enabled = false;
            try
            {
                this.dgvCache.Rows.Clear();
                this.dgvCache.Columns.Clear();
                if (this.tscbRegion.SelectedIndex != 0)
                {
                    this.dgvCache.Columns.Add(new DataGridViewTextBoxColumn() { HeaderText = "_key", Name = "col_key", ValueType = typeof(string) });
                    foreach (PropertyInfo pi in _schemas[this.tscbRegion.SelectedItem.ToString()].GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.SetProperty))
                    {
                        this.dgvCache.Columns.Add(new DataGridViewTextBoxColumn() { HeaderText = pi.Name, Name = string.Concat("col",pi.Name), ValueType = typeof(string) });
                    }
                }
                this.tscbView.Items.Clear();
                this.tscbView.Items.Add("<==NoUse==>");
                if (this._views.ContainsKey(this.tscbRegion.SelectedItem.ToString()))
                {
                    this.tscbView.Items.AddRange(this._views[this.tscbRegion.SelectedItem.ToString()].ToArray());
                }
                this.tscbView.SelectedIndex = 0;
            }
            catch (Exception ex)
            {
                MessageBoxHelper.ShowError(ex.Message);
            }
            finally
            {
                this.Enabled = true;
            }
        }
    }
}
